#pragma once
#include "MessagePubSubTypes.h"
#include "ComDefine.h"
#include <fastdds/dds/domain/DomainParticipant.hpp>
#include <fastdds/dds/subscriber/Subscriber.hpp>
#include <fastdds/dds/subscriber/DataReader.hpp>
#include <fastdds/dds/subscriber/DataReaderListener.hpp>
#include <fastdds/dds/subscriber/SampleInfo.hpp>

#include <vector>
#include <fstream>
#include <condition_variable>
#include <mutex>
#include <atomic>
#include <thread>
#include <unordered_map>
#include <QObject>


namespace Test {
    struct SubscriberStructer {
        eprosima::fastdds::dds::DataReader* reader;
        eprosima::fastdds::dds::Topic* topic;
    };
    struct SubParticipantStructer {
        eprosima::fastdds::dds::Subscriber* subs;
        eprosima::fastdds::dds::DomainParticipant* ptcp;
        std::unordered_map<std::string, SubscriberStructer> topic_readers;
    };


    class LogMsg {
    public:
        ~LogMsg();
        void init(std::string logFile);
        void appendMsg(const Message& msg);
        void run();
        void stop();
    private:
        std::ofstream ofs;
        std::string strMsg;
        std::mutex mutex_;
        std::condition_variable cond_;
        // std::atomic_bool running_;
    };
};
class TestSubscriber;
class SubListener : public QObject, public eprosima::fastdds::dds::DataReaderListener
{
    Q_OBJECT
    friend TestSubscriber;
private:

    SubListener()
        : matched_(0)
        , samples_(0)
    {
    }

    ~SubListener() override
    {
        logMsg_.stop();
        if (thread_.joinable()) {
            thread_.join();
        }
        printf("~SubListener\n");
    }
    void setLogMsg(std::string logFile) {
        logMsg_.init(logFile);
        std::thread t(&Test::LogMsg::run, &logMsg_);
        //std::cin.ignore();

        //t.join();
        thread_.swap(t);
    }
    void stopLog() {
        logMsg_.stop();
        if (thread_.joinable()) {
            thread_.join();
        }
    }
    void on_data_available(
        eprosima::fastdds::dds::DataReader* reader) override;

    void on_subscription_matched(
        eprosima::fastdds::dds::DataReader* reader,
        const eprosima::fastdds::dds::SubscriptionMatchedStatus& info) override;

    Message message_;

    int matched_;
    std::thread thread_;
    uint32_t samples_;
    Test::LogMsg logMsg_;
signals:
    void sigTestSubscriber(Message);
};
class TestSubscriber :public QObject
{
    Q_OBJECT
public:

    TestSubscriber();

    ~TestSubscriber();
    bool createSubscriber(InitParam param);
    //!RUN the subscriber
    void run(std::string logFile);
    void stop();
    void freeAll();
private:
    eprosima::fastdds::dds::DomainParticipant* createParticipant(InitParam param);
    eprosima::fastdds::dds::Subscriber* createSubscriber(InitParam param, eprosima::fastdds::dds::DomainParticipant*);
    eprosima::fastdds::dds::Topic* createTopic(InitParam param, eprosima::fastdds::dds::DomainParticipant*);
    eprosima::fastdds::dds::DataReader* createReader(InitParam param, eprosima::fastdds::dds::Subscriber*, eprosima::fastdds::dds::Topic*);
private:

    eprosima::fastdds::dds::TypeSupport type_;
    //std::unordered_map <std::string, eprosima::fastdds::dds::DomainParticipant*> name_participant_;
    //std::unordered_map<std::string, std::unordered_map<std::string, eprosima::fastdds::dds::Subscriber*>> participant_topic_subscriber;
    std::unordered_map<std::string, Test::SubParticipantStructer> participant_structer_;
    SubListener listener;
public slots:
    void slotTestSubscriber(Message);
signals:
    void sigPublish(Message);
};